<template>
    <div class="vue-draw" :class="{fullscreen: isEdit}">
        <template v-if="!isEdit">
            <img v-if="/(.png|.jpg|.webp|.jpeg|.PNG|.JPG|.WEBP|.JPEG|http|https)/g.test(preImg)" :src="preImg" class="vd-bg" @click="open" @error="imgError">
            <div v-else :style="{background: preImg, width: '100%', height: '100%'}" @click="open"></div>
        </template>
        <div v-show="isEdit" class="vd-view" ref="vdView">
            <div class="canvas-box" ref="canvasBox">
                <canvas ref="CANVAS" style="max-width: 100%;width: 100%;"></canvas>
            </div>
        </div>
        <div class="vd-loading-view" v-if="isEdit && isLoading">
            <i class="iconfont icon-drawjiazai--kuai vd-loading"></i>
        </div>
        <div class="vd-controls" v-if="controlList.length > 0 && isEdit && !disabled">
            <template v-for="(item, i) in controlList">
                <i :title="item.name"
                   :class="['iconfont', item.icon, activeControl === item.type ? 'active' : '', disabledControl[item.type] ? 'disabled' : '']"
                   @click="onSelectControl(item, i)"></i>
            </template>
            <div class="vd-font-color-view" :style="'left: ' + colorLeft +'px'" v-if="currentControlItem.isColor">
                <template v-if="activeControl === 'Text'">
                    <span v-for="s in fonts" class="vd-f-item"
                          :class="[s.type, s.size === defDrawOptions.fontSize ? 'active' : '']"
                          @click="selectFont(s)"><i></i></span>
                </template>
                <template v-else>
                    <span v-for="s in size" class="vd-f-item"
                          :class="[s.type, s.size === defDrawOptions.lineWidth ? 'active' : '']" @click="selectLine(s)"><i></i></span>
                </template>
                <span v-for="c in colors" class="vd-c-item" :class="[c, defDrawOptions.color === c ? 'active' : '']"
                      :style="'background: ' + c" @click="selectColor(c)"></span>
            </div>
        </div>
    </div>
</template>

<script>
import './font/iconfont.css'
import _plugins from "./plugins/index";
import {
    UUID,
    varType,
    drawImgToCanvas,
    drawCircle,
    lineArrow,
    drawPen,
} from './utils';

export default {
    name: "vueDraw",
    props: {
        background: {
            type: String,
            default: '',
            desc: '编辑器默认背景图'
        },
        disabled: {
            type: Boolean,
            default: false,
            desc: '是否禁用编辑器'
        },
        config: {
            type: Object,
            default: () => {},
            desc: '编辑器配置文件',
            attribute: {
                open: '是否打开编辑器',
                downloadTitle: '下载图片的名称',
                controls: {
                    type: Array,
                    default: [],
                    desc: '控制按钮'
                }
            }
        }
    },
    data() {
        return {
            colorLeft: -101,
            currentControlItem: {},
            bgUrl: null, //背景图
            isEdit: false, //是否在编辑
            isLoading: false,
            activeControl: null,
            colors: ['red', 'orange', 'blue', '#05af05', '#2e2c2c', 'white'],
            fonts: [
                {type: 'mini', size: 16, txt: '小'},
                {type: 'middle', size: 20, txt: '中'},
                {type: 'big', size: 30, txt: '大'}
            ],
            size: [
                {type: 'mini', size: 2},
                {type: 'middle', size: 4},
                {type: 'big', size: 6}
            ],
            defDrawOptions: {
                lineWidth: 4,
                color: 'red',
                fontSize: 20,
            },
            ctrls: [
                {type: 'Square', name: '方框（Ctrl + Q）', icon: 'icon-drawfangkuang4', isColor: true},
                {type: 'Circle', name: '圆（Ctrl + C）', icon: 'icon-drawyuanxingweixuanzhong', isColor: true},
                {type: 'Line', name: '箭头（Ctrl + L）', icon: 'icon-drawleftbottom', isColor: true},
                {type: 'Pen', name: '画笔（Ctrl + P）', icon: 'icon-drawhuabi', isColor: true},
                {type: 'Text', name: '文字（注意：内容超出绘画区域会丢失额~）', icon: 'icon-drawfont-size', isColor: true, isFont: true},
                // {type: 'MaSaiKe', name: '橡皮擦', icon: 'icon-drawxiangpica1'},
                {type: 'Rotate', name: '旋转（Ctrl + R）', icon: 'icon-drawloop'},
                {type: 'ZoomIn', name: '放大（Ctrl + +）', icon: 'icon-drawfangda2'},
                {type: 'ZoomOut', name: '缩小（Ctrl + -）', icon: 'icon-drawsuoxiao1'},
                {type: 'Down', name: '下载（Ctrl + D）', icon: 'icon-drawxiazai'},
                {type: 'Revoke', name: '撤销（Ctrl + Z）', icon: 'icon-drawfanhui4'},
                {type: 'Close', name: '关闭', icon: 'icon-drawchahao'},
                {type: 'Save', name: '保存', icon: 'icon-drawduigou'}
            ],
            controlList: [{type: 'Close', name: '关闭', icon: 'icon-drawchahao'}],
            disabledControl: {Revoke: true, Rotate: false},
            width: 0,
            height: 0,
            preImg: null,
        }
    },
    mounted() {
        //唯一标识
        this.uuid = UUID();
        //初始化数据
        this.zoomScale = 0
        this.scale = 1
        this.data = []
        varType.init.apply(this);
        this.options = Object.assign({}, {
            pixel: 0,
        }, this.config || {});

        let {controls, open} = this.options;
        this.preImg = this.background;
        if(Array.isArray(controls) && controls.length > 0){
            let c = {};
            let list = [];
            this.ctrls.map(item => ( c[item.type] = item))
            controls.map(item => list.push(c[item]))
            if(list.length > 0){
                list.push(c['Revoke'])
            }
            if(controls.indexOf('Close') < 0){
                list.push(c['Close'])
            }
            this.controlList = list;
        }else{
            this.controlList = [...this.ctrls]
        }
        this.$nextTick(() => {
            if(open){
                this.open()
            }
        })
    },
    methods: {
        resetOpt() {
            this.defDrawOptions = {
                lineWidth: 4,
                color: 'red',
                fontSize: 20,
            }
        },
        selectLine(l) {
            this.defDrawOptions.lineWidth = l.size;
        },
        selectFont(f) {
            this.defDrawOptions.fontSize = f.size;
            this.controlEvent('fontChange', f.size)
        },
        selectColor(c) {
            this.defDrawOptions.color = c;
            this.controlEvent('colorChange', c)
        },
        open() {
            this.controlEvent('click', null, 'Open')
        },
        initEvent() {
            const canvas = this.canvas;
            canvas.onmousedown = e => {
                e = e || window.event;
                this.controlEvent('canvasMousedown', e)
            }
            canvas.onmouseup = e => this.controlEvent('canvasMouseup', e);
            canvas.onmouseout = e => this.controlEvent('canvasMouseout', e);
            canvas.ontouchstart = e => this.controlEvent('canvasTouchstart', e);
            canvas.ontouchend = e => this.controlEvent('canvasTouchend', e);
            window.addEventListener('mouseup', this.mouseup, true);
            window.addEventListener('mousemove', this.mousemove, true);
            window.addEventListener('touchend', this.touchend, true);
            window.addEventListener('touchmove', this.touchmove, true);
            window.addEventListener('visibilitychange', this.visibilitychange, true)
        },
        mousedown(e) {
            e = e || window.event;
            if (this.isEdit) {
                this.controlEvent('winMouseDown', e)
            }
        },
        mouseup(e) {
            e = e || window.event;
            if (this.isEdit) {
                this.controlEvent('winMouseup', e)
            }
        },
        mousemove(e) {
            e = e || window.event;
            if (this.isEdit && this.activeControl) {
                this.controlEvent('winMousemove', e)
            }
        },
        touchend(e) {
            if (this.isEdit) {
                this.controlEvent('winTouchend', e)
            }
        },
        touchmove(e) {
            if (this.isEdit && this.activeControl) {
                this.controlEvent('winTouchMove', e)
            }
        },
        visibilitychange(e) {
            if (this.isEdit) {
                this.controlEvent('visibilitychange', e)
            }
        },
        initCanvas(image) {
            const canvas = this.canvas = this.$refs.CANVAS;
            if(image){
                canvas.width = image.width;
                canvas.height = image.height;
                this.ctx = canvas.getContext('2d');
                this.canvasRect = {width: image.width, height: image.height}
                drawImgToCanvas(this.ctx, image, 0, 0, image.width, image.height);
            }else{
                canvas.width = this.width;
                canvas.height = this.height;
                this.ctx = canvas.getContext('2d');
                this.canvasRect = {width: this.width, height: this.height}
                this.ctx.fillStyle = this.background
                this.ctx.fillRect(0, 0, this.canvasRect.width, this.canvasRect.height)
            }

        },
        imgError(e) {
            this.error({message: '初始化图片失败，请检查资源或资源地址是否设置跨域限制', error: e, url: this.background, origin: 'imgError'});
        },
        loading(bool) {
            this.isLoading = bool
        },
        error(options) {
            this.$emit('error', Object.assign({
                type: 'error'
            }, options))
        },
        onSelectControl(item, i) {
            if (item.isColor && item.type === this.currentControlItem.type) {
                this.currentControlItem = {};
                this.activeControl = null;
                return;
            }

            if (this.data.length === 0) {
                this.disabledCtrl('Rotate', false)
            }

            if (item.isColor || item.isFont) {
                this.resetOpt();
            }
            //计算颜色框的位置
            this.colorLeft = -101 + (i * 40);
            this.currentControlItem = item;
            this.controlList.forEach(tem => (this[`is${tem.type}`] = false))
            if (this.disabledControl[item.type]) {
                return this.activeControl = null;
            }
            this[`is${item.type}`] = true;
            if (!(['Close', 'Save'].includes(item.type))) {
                this.activeControl = item.type;
            } else {
                this.activeControl = null;
            }
            this.controlEvent('click', null, item.type)
        },
        controlEvent(key, e, type) {
            type = type || (this.currentControlItem ? this.currentControlItem.type : 'Init');
            if (!type) return;
            let p = _plugins[type];
            if (p && this.isFunction(p[key])) {
                (p[key]).apply(this, [e])
            } else {
                // console.error(new Error(`插件${type}的${key}不是一个Function`))
            }
        },
        eventDestroy() {
            window.removeEventListener('mouseup', this.mouseup, true);
            window.removeEventListener('mousemove', this.mousemove, true);
            window.removeEventListener('touchend', this.touchend, true);
            window.removeEventListener('touchmove', this.touchmove, true);
            window.removeEventListener('visibilitychange', this.visibilitychange, true);
        },
        save(item) {
            this.data.push(item)
            this.isChange = true
            if (this.data.length > 0) {
                this.disabledCtrl('Revoke', false)
                this.disabledCtrl('Rotate', true)
            }
        },
        disabledCtrl(key, val) {
            this.disabledControl[key] = val
        },
        restDraw(bool) {
            let ctx = this.ctx;
            ctx.clearRect(0, 0, this.canvasRect.width, this.canvasRect.height)
            ctx.putImageData(this.imgDataOld, 0, 0)

            for (let i = 0, len = this.data.length; i < len; i++) {
                let {type, ys, xw, x, y, x1, y1, x2, y2, w, h, pos, font, value} = this.data[i];
                if (type === 'Square') {
                    ctx.strokeStyle = ys
                    ctx.lineWidth = xw
                    ctx.strokeRect(x, y, w, h)
                } else if (type === 'Circle') {
                    drawCircle(ctx, x, y, w, h, ys, xw)
                } else if (type === 'Line') {
                    lineArrow(ctx, {x: x1, y: y1}, {x: x2, y: y2}, ys, xw)
                } else if (type === 'Pen') {
                    for (let j = 0, len = pos.length; j < len; j++) {
                        if (pos[j + 1]) {
                            drawPen(ctx, pos[j], pos[j + 1], ys, xw)
                        }
                    }
                } else if (type === 'Text' && !bool) {
                    ctx.font = `bold ${font + 2}px cursive`;
                    ctx.fillStyle = ys;
                    ctx.textBaseline = "top";
                    ctx.wrapText(value, x + 2, y + 7, this.getLineHeight(font.fontSize));
                }
            }
        },
        getLineHeight(size) {
            if (size === 16) {
                return 16
            }
            if (size === 20) {
                return 20
            }
            if (size === 30) {
                return 30
            }
        },
        drawFont(bool) {
            for (let i = 0; i < this.data.length; i++) {
                let item = this.data[i];
                if (item.type === 'Text') {
                    this.ctx.font = `bold ${item.font + 2}px cursive`;
                    this.ctx.fillStyle = item.ys;
                    this.ctx.textBaseline = "top";
                    this.ctx.wrapText(item.value, item.x + 2, item.y + 4, this.getLineHeight(item.font));
                    if (bool) {
                        let el = document.getElementById(item.id)
                        if (el) {
                            el.style.display = 'none'
                        }
                    }
                }
            }
        }
    }
}
</script>

<style scoped lang="scss">
.vue-draw {
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    .canvas-box {
        display: inline-block;
        position: relative;
    }

    .vd-font-color-view {
        background: #fff;
        position: absolute;
        z-index: 999;
        display: flex;
        align-items: center;
        justify-content: center;
        bottom: -42px;
        left: 0;
        padding: 8px;
        border-radius: 3px;

        &:before {
            position: absolute;
            content: '';
            width: 8px;
            height: 8px;
            background: #fff;
            left: 50%;
            z-index: 99;
            top: -4px;
            transform: rotate(45deg);
        }

        > span {
            display: inline-block;
            margin: 0 3px;
            width: 18px;
            height: 18px;
        }
    }

    .vd-c-item {
        position: relative;
        padding: 0;
        border-radius: 1px;

        &.white {
            border: 1px solid #ebebeb;
            width: 16px;
            height: 16px;

            &:hover {
                background: #d9d7d7 !important;
                width: 18px;
                height: 18px;
                border: none
            }
        }

        &:before {
            content: '';
            width: 8px;
            height: 9px;
            background: transparent;
            position: absolute;
            left: 5px;
            top: 5px;
            z-index: 1;
            padding: 0;
            margin: 0;
            border-radius: 1px;
        }

        &:hover:before {
            background: #fff;
        }

        &.active:before {
            background: #fff;
        }

        &.white.active {
            background: #d9d7d7 !important;
            width: 18px;
            height: 18px;
            border: none
        }
    }

    .vd-f-item {
        display: flex !important;
        align-items: center;

        > i {
            display: inline-block;
            border-radius: 50%;
            background: #afafaf;
            width: 8px;
            height: 8px;

            &:hover {
                background: #0dcb0d;
            }
        }

        &.active > i {
            background: #0dcb0d;
        }

        &.middle > i {
            width: 11px;
            height: 11px;
        }

        &.big > i {
            width: 14px;
            height: 14px;
        }
    }

    &.fullscreen {
        width: 100vw;
        height: 100vh;
        position: fixed;
        left: 0;
        top: 0;
        z-index: 9999999;
        padding: 20px;
        background: rgba(0, 0, 0, 0.21);
    }

    .vd-bg {
        max-width: 100%;
        max-height: 100%;
        cursor: pointer;
    }

    .vd-view {
        width: 100%;
        height: calc(100% - 115px);
        overflow: auto;
        text-align: center;
        background: rgb(74, 75, 75);
        position: relative;
        box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.7);

        &::-webkit-scrollbar-thumb {
            border-radius: 10px;
            -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.3);
            background: transparent;
        }

        &::-webkit-scrollbar-track {
            -webkit-box-shadow: inset 0 0 5px rgba(108, 108, 108, 0);
            border-radius: 10px;
            background: transparent;
        }

        &::-webkit-scrollbar-thumb:vertical {
            background-color: #BDBDBD;
            -webkit-border-radius: 6px;
        }

        &::-webkit-scrollbar-thumb:horizontal {
            background-color: #BDBDBD;
            -webkit-border-radius: 6px;
        }

    }

    canvas {
        cursor: pointer;
    }

    .vd-controls {
        min-width: 35px;
        height: 35px;
        background: #fff;
        position: absolute;
        bottom: 97px;
        right: 20px;
        z-index: 99;
        border-radius: 0;
        display: flex;
        align-items: center;
        justify-content: center;

        > i {
            cursor: pointer;
            padding: 0 10px;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all .05s ease-out;
            font-size: 20px;
            color: #4a4a4cfa;

            &:hover {
                background: #d3d3d3cf;
            }

            &.active {
                background: #a45fff;
                color: #fff;
            }

            &.icon-drawduigou {
                font-size: 23px;
            }

            &.disabled {
                background: #d3d3d3cf;
                cursor: no-drop;
                color: #bbb;
            }
        }
    }

    .vd-loading-view {
        position: absolute;
        width: calc(100% - 40px);
        height: calc(100% - 80px);
        z-index: 99;
        background: #ffffff7a;
        top: 20px;
        left: 20px;
        display: flex;
        justify-content: center;
        align-items: center;

        i {
            font-size: 50px;
            color: #f1e9ff;
        }
    }

    .vd-loading {
        animation: rotate 1s linear infinite;
    }

    @keyframes rotate {
        0% {
            transform: rotate(0deg);
        }
        100% {
            transform: rotate(360deg);
        }
    }
}
</style>
